package net.sunzc.yunlian.view;

import com.android.ddmlib.*;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SeparatorMenuItem;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.FileChooser;
import net.sunzc.yunlian.controller.GroupControllable;
import net.sunzc.yunlian.controller.GroupController;
import net.sunzc.yunlian.controller.entity.CircleDirectory;
import net.sunzc.yunlian.controller.entity.MousePoint;
import net.sunzc.yunlian.controller.entity.Point;
import net.sunzc.yunlian.interact.device.AndroidDevice;
import net.sunzc.yunlian.interact.device.command.Command;
import net.sunzc.yunlian.interact.device.command.CommonCommand;
import net.sunzc.yunlian.interact.device.factory.AdbInputCommandFactory;
import net.sunzc.yunlian.interact.device.factory.BroadcastCommandFactory;
import net.sunzc.yunlian.interact.keyboard.InputKeyEvent;
import net.sunzc.yunlian.utils.Utils;
import net.sunzc.yunlian.view.entity.PhoneBook;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

import static net.sunzc.yunlian.FxApp.stage;

/**
 * Created by Sun on 2016/6/5.
 */
public class ScreenWindow extends VBox implements AndroidScreen, GroupControllable {
    private static final String REMOTE_FILE_PATH = "/sdcard/";
    private static final String TAG = "AndroidDevice";
    @FXML
    public AnchorPane screenPane;
    @FXML
    public ImageView screenView;
    private GroupController groupController;
    private AndroidDevice mAndroidDevice;
    private ContextMenu cm;
    private SendTextField sendTextField;
    private Number number;
    private long last;

    public ScreenWindow(IDevice device) {
        mAndroidDevice = new AndroidDevice(device);
        mAndroidDevice.setProjectScreen(this);
        groupController = GroupController.getController();
        GroupController.register(this);
        initScreen();
    }

    private void initScreen() {
        DialogUtils.bindFXML(this, "screen_window.fxml");
        setEffect(new DropShadow(3, Color.BLUEVIOLET));
        sendTextField = new SendTextField(mAndroidDevice);
        number = new Number();
        screenPane.getChildren().add(number);
        AnchorPane.setRightAnchor(number, 10.0);
        AnchorPane.setTopAnchor(number, 10.0);
        screenView.setSmooth(true);
        screenView.fitWidthProperty().addListener((observable, oldValue, newValue) -> {
            setPrefWidth(newValue.doubleValue());
        });
        String frameSize = mAndroidDevice.getFrameSize();
        String widthStr = frameSize.split("x")[0];
        String heightStr = frameSize.split("x")[1];
        screenView.setFitWidth(Double.valueOf(widthStr));
        screenView.setFitHeight(Double.valueOf(heightStr));
        setPrefWidth(Double.valueOf(widthStr));
    }

    @FXML
    public void refreshDevice(ActionEvent event) {
        mAndroidDevice.restart();
    }

    public void onHomePressed(ActionEvent event) {
        if (groupController.isController(this)) {
            groupController.onHomePressed(event);
        }
        pressKey(InputKeyEvent.KEYCODE_HOME);
    }

    private void pressKey(InputKeyEvent keyEvent) {
        Utils.threadPool.execute(() -> {
                    try {
                        mAndroidDevice.shellExecute(
                                AdbInputCommandFactory.getKeyCommand(keyEvent)
                        );
                    } catch (TimeoutException | AdbCommandRejectedException | IOException | ShellCommandUnresponsiveException e) {
                        e.printStackTrace();
                        Log.e(TAG, "按键失败" + keyEvent.toString());
                    }
                }
        );
    }

    public void onBackPressed(ActionEvent event) {
        if (groupController.isController(this)) {
            groupController.onBackPressed(event);
        }
        pressKey(InputKeyEvent.KEYCODE_BACK);
    }

    public void onLockPressed(ActionEvent event) {
        if (groupController.isController(this)) {
            groupController.onLockPressed(event);
        }
        pressKey(InputKeyEvent.KEYCODE_POWER);
    }

    public void onStartClient(ActionEvent event) {
        if (groupController.isController(this)) {
            groupController.onStartClient(event);
        }
        mAndroidDevice.openClient();
    }

    @FXML
    public void onMouseEntered(MouseEvent event) {
    }

    @FXML
    public void onMouseExited(MouseEvent event) {
    }

    @FXML
    public void onMouseClicked(MouseEvent event) {
        switch (event.getButton()) {
            case PRIMARY:
                screenView.requestFocus();
                screenView.setFocusTraversable(true);
                break;
            case SECONDARY:
                cm = getContextMenu(event);
                cm.show(screenView, event.getScreenX(), event.getScreenY());
                break;
            default:
                break;
        }
        event.consume();
    }

    private ContextMenu getContextMenu(MouseEvent mouseEvent) {
        ContextMenu cm = new ContextMenu();
        MenuItem asController = new MenuItem(groupController.isController(this) ? "取消群控" : "设为主控");
        asController.setOnAction(e -> {
            if (groupController.isController(ScreenWindow.this)) {
                groupController.cancelControl();
            } else {
                groupController.setController(this);
            }
        });
        MenuItem sendCircleItem = null;
        if (groupController.isController(this)) {
            sendCircleItem = new MenuItem("群发朋友圈");
            sendCircleItem.setOnAction(event -> {
                CircleDirectory srcFileDir = DialogUtils.getCircleDirectory();
                if (srcFileDir != null) {
                    Log.i(TAG, srcFileDir.toString());
                    String zipFilePath = srcFileDir.getZipFile();
                    sendCircle(zipFilePath);
                }
            });
        }
        MenuItem screenCap = new MenuItem("截屏");
        screenCap.setOnAction(e -> {
            takeScreenShot();
        });
        cm.setAutoHide(true);
        cm.setHideOnEscape(true);
        cm.focusedProperty().addListener((observable, oldValue, newValue) -> {
            if (!newValue) cm.hide();
        });
        MenuItem addToText = new MenuItem("输入文字");
        //此处修复多次弹出输入框的问题
        if (sendTextField != null && screenPane.getChildren().contains(sendTextField)) {
            screenPane.getChildren().remove(sendTextField);
        }
        addToText.setOnAction(event -> {
            sendTextField.setInputBoxWith(getPrefWidth());
            double positionY = mouseEvent.getY() + 30;
            if (positionY < screenPane.getHeight()) {
                AnchorPane.setTopAnchor(sendTextField, positionY);
            } else {
                AnchorPane.setBottomAnchor(sendTextField, 0d);
            }
            AnchorPane.setRightAnchor(sendTextField, 0d);
            AnchorPane.setLeftAnchor(sendTextField, 0d);
            screenPane.getChildren().add(sendTextField);
            sendTextField.requestFocus();
        });
        if (sendCircleItem != null) {
            cm.getItems().addAll(asController, sendCircleItem, new SeparatorMenuItem(), screenCap, addToText);
        } else
            cm.getItems().addAll(asController, new SeparatorMenuItem(), screenCap, addToText);
        return cm;
    }

    @FXML
    public void onMousePressed(MouseEvent event) {
        Log.i(TAG, "onMousePressed");
        switch (event.getButton()) {
            case PRIMARY:
                mAndroidDevice.onDown(getMousePoint(event));
                if (groupController.isController(this)) {
                    groupController.onMousePressed(event);
                }
                if (screenPane.getChildren().contains(sendTextField)) {
                    screenPane.getChildren().remove(sendTextField);
                }
                if (cm != null && cm.isShowing()) {
                    cm.hide();
                    event.consume();
                }
        }
    }

    private Point getMousePoint(MouseEvent event) {
        return MousePoint.getPoint(event, mAndroidDevice.getScaleRate());
    }

    @FXML
    public void onKeyReleased(KeyEvent event) {
        if (groupController.isController(this)) {
            groupController.onKeyReleased(event);
        }
        InputKeyEvent keyEvent;
        switch (event.getCode()) {
            case BACK_SPACE:
                keyEvent = InputKeyEvent.KEYCODE_DEL;
                break;
            case DELETE:
                keyEvent = InputKeyEvent.KEYCODE_FORWARD_DEL;
                break;
            case ESCAPE:
                keyEvent = InputKeyEvent.KEYCODE_BACK;
                break;
            case SPACE:
                keyEvent = InputKeyEvent.KEYCODE_MENU;
                break;
            case HOME:
                keyEvent = InputKeyEvent.KEYCODE_HOME;
                break;
            case SCROLL_LOCK:
                keyEvent = InputKeyEvent.KEYCODE_POWER;
                break;
            case UP:
                keyEvent = InputKeyEvent.KEYCODE_VOLUME_UP;
                break;
            case DOWN:
                keyEvent = InputKeyEvent.KEYCODE_VOLUME_DOWN;
                break;
            case PAGE_DOWN:
                keyEvent = InputKeyEvent.KEYCODE_PAGE_DOWN;
                break;
            case PAGE_UP:
                keyEvent = InputKeyEvent.KEYCODE_PAGE_UP;
                break;
            default:
                return;
        }
        pressKey(keyEvent);
        event.consume();
    }

    @FXML
    public void onMouseDragged(MouseEvent event) {
        Log.i(TAG, "onMouseDragged");
        switch (event.getButton()) {
            case PRIMARY:
                mAndroidDevice.onTouch(getMousePoint(event));
                if (groupController.isController(this))
                    groupController.onMouseDragged(event);
                break;
            default:
                break;
        }
        event.consume();
    }

    @FXML
    public void onMouseReleased(MouseEvent event) {
        Log.i(TAG, "onMouseReleased");
        switch (event.getButton()) {
            case PRIMARY:
                if (groupController.isController(this))
                    groupController.onMouseReleased(event);
                mAndroidDevice.onRelease();
                break;
            default:
                break;
        }
        event.consume();
    }

    @Override
    public void asController() {
        screenView.requestFocus();
        screenView.setEffect(new DropShadow(5, Color.RED));
    }

    @Override
    public void releaseController() {
        screenView.setEffect(null);
        screenView.setFocusTraversable(false);
    }

    private File modifySerial(String value) {
        List<String> list = new ArrayList<>();
        File buildPropFile = new File(System.getProperty("user.dir"), "build.prop");
        BufferedReader br;
        try {
            br = new BufferedReader(new FileReader(buildPropFile));
            String line;
            while ((line = br.readLine()) != null) {
                if (line.contains("ro.usb.sn"))
                    line = "ro.usb.sn=" + value;
                list.add(line);
            }
            br.close();
            buildPropFile.delete();
            buildPropFile.createNewFile();
            BufferedWriter bw = new BufferedWriter(new FileWriter(buildPropFile));
            for (String str : list) {
                bw.write(str);
                bw.newLine();
                bw.flush();
            }
            bw.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return buildPropFile;
    }

    @FXML
    public void onSerial(ActionEvent event) throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException {
        String serial = DialogUtils.showInputDialog("修改串号", "请输入新串号", "");
        if (serial == null || "".equals(serial)) return;
        File buildPropFile = modifySerial(serial);
        mAndroidDevice.pushFile(buildPropFile.getAbsolutePath(), "/sdcard/" + buildPropFile.getName());
        String mountRWCommand = "mount -o remount,rw /dev/block/platform/mtk-msdc.0/by-name/system /system";
        mAndroidDevice.shellExecute(CommonCommand.getCommand("su -c '" + mountRWCommand + "'"));
        String command = "cp -f /sdcard/" + buildPropFile.getName() + " /system/";
        mAndroidDevice.shellExecute(CommonCommand.getCommand("su -c '" + command + "'"));
        String mountROCommand = "mount -o remount,ro /dev/block/platform/mtk-msdc.0/by-name/system /system";
        mAndroidDevice.shellExecute(CommonCommand.getCommand("su -c '" + mountROCommand + "'"));
        try {
            mAndroidDevice.getDevice().reboot("");
        } catch (TimeoutException | AdbCommandRejectedException | IOException e) {
            e.printStackTrace();
            Log.e(TAG, "重启失败");
        }
    }

    public void onLogin(ActionEvent event) {
        if (groupController.isController(this)) {
            groupController.onLogin(event);
        }
        PhoneBook phoneBook = DialogUtils.showLoginDialog("软件登录验证", "验证");
        if (phoneBook == null) return;
        BroadcastCommandFactory.Extras extras = new BroadcastCommandFactory.Extras();
        extras.putExtras(BroadcastCommandFactory.Extras.EXTRAS_PASSWORD, phoneBook.getPassword());
        extras.putExtras(BroadcastCommandFactory.Extras.EXTRAS_EMAIL, phoneBook.getUser());
        Command broadcastCommand = BroadcastCommandFactory.getBroadcastCommand(BroadcastCommandFactory.BroadcastAction.START_LOGIN, extras);
//        mAndroidDevice.shellExecute(broadcastCommand);
    }

    @Override
    public void sendCircle(String circleZipPath) {
        if (groupController.isController(this)) {
            groupController.sendCircle(circleZipPath);
        }
        Utils.threadPool.execute(() -> {
            mAndroidDevice.pushFile(circleZipPath, REMOTE_FILE_PATH + CircleDirectory.ZIP_FILE_NAME);
            Log.i(TAG, "发送文件到" + circleZipPath + "----->" + REMOTE_FILE_PATH + CircleDirectory.ZIP_FILE_NAME);
            //把文件打包发送，发送完成后发送通知，发朋友圈开始
            BroadcastCommandFactory.Extras extras = new BroadcastCommandFactory.Extras();
            extras.putExtras(BroadcastCommandFactory.Extras.EXTRAS_TIME, 0);
            Command broadcastCommand = BroadcastCommandFactory.getBroadcastCommand(BroadcastCommandFactory.BroadcastAction.SEND_CIRCLE, extras);
            try {
                mAndroidDevice.shellExecute(broadcastCommand);
            } catch (TimeoutException | AdbCommandRejectedException | ShellCommandUnresponsiveException | IOException e) {
                e.printStackTrace();
                Log.e(TAG, "朋友圈命令发送失败");
            }
        });
    }

    private void takeScreenShot() {
        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("保存截图");
        fileChooser.setInitialDirectory(
                new File(System.getProperty("user.dir"))
        );
        fileChooser.getExtensionFilters().add(
                new FileChooser.ExtensionFilter("PNG", "*.png")
        );
        File file = fileChooser.showSaveDialog(stage);
        if (file != null)
            mAndroidDevice.takeScreenShot(file.getAbsolutePath());
    }

    void stop() {
        mAndroidDevice.stop();
        GroupController.unregister(this);
    }

    @Override
    public void projectScreenImage(Image image) {
        if (image != null) {
            screenView.setImage(image);
//            long current = System.currentTimeMillis();
//            Log.i(TAG, mAndroidDevice.getSerialNum() + ":投射屏幕:" + (current - last));
//            last = current;
        }
    }

    @Override
    public void updateScreenNumber(int number) {
        this.number.setText(String.valueOf(number));
    }

    public String getSerialNum() {
        return mAndroidDevice.getSerialNum();
    }
}
